﻿using System;
using System.ComponentModel;

namespace Notoric.ViewModel.Elements.CWNotation
{
    /// <summary>
    /// Represents one augmentation dot.
    /// </summary>
    /// <remarks>
    /// The dot only includes its horizontal <see cref="Position"/>. The vertical position
    ///  must be supplied by its owner. For a <see cref="Rest"/> the position is usually
    ///  the 3rd staff line. For a <see cref="Chord"/> the dot is drawn to each <see cref="Note"/>.
    /// </remarks>
    public class AugmentationDot : VirtualViewModelElement
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="AugmentationDot"/> instance.
        /// </summary>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="DurationalSymbol"/>
        /// </para>
        /// <para>
        /// The symbol that directly owns this dot.
        /// </para>
        /// </param>
        /// <param name="order">
        /// <para>
        /// Type: <see cref="Int32"/>
        /// </para>
        /// <para>
        /// The order of the dot (first dot has order 0).
        /// </para>
        /// </param>
        internal AugmentationDot(DurationalSymbol owner, int order)
            : base(owner)
        {
            this.order = order;
            RegisterToOwnerPropertyChanged<DurationalSymbol>();
            RegisterToOwnerPropertyChanged<Staff>();
        }

        #endregion

        #region VirtualViewModelElement Members

        /// <inheritdoc/>
        public override void Dispose()
        {
            UnregisterFromOwnerPropertyChanged<DurationalSymbol>();
            UnregisterFromOwnerPropertyChanged<Staff>();
            base.Dispose();
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the value of some owner's property has changed.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// If the modified property is <see cref="CoreSymbol.Position"/>, the handler raises
        /// the <see cref="VirtualViewModelElement.PropertyChanged"/> event for the <see cref="Position"/> property.
        /// </remarks>
        /// <param name="owner">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        protected override void Owner_PropertyChanged(ViewModelElement owner, PropertyChangedEventArgs e)
        {
            if (owner is DurationalSymbol && (e.PropertyName == "Position" || e.PropertyName == "DotsOffset"))
                RaisePropertyChanged("Position");
            else if (owner is Staff && e.PropertyName == "SpaceSize")
                RaisePropertyChanged("Position");
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the order of this augmentation dot.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Int32"/>
        /// </para>
        /// <para>
        /// The order of the augmentation dot (first dot has order 0, second 1, etc.)
        /// </para>
        /// </value>
        public int Order
        {
            get { return order; }
        }

        /// <summary>
        /// Gets the position of the dot.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Double"/>
        /// </para>
        /// <para>
        /// The horizontal position (in device independent pixels) of this dot (including the position of the owner).
        /// </para>
        /// </value>
        public double Position
        {
            get 
            {
                var spaceSize = FindOwner<Staff>().SpaceSize;
                var symbol = FindOwner<DurationalSymbol>();
                var position = symbol.Position + symbol.DotsOffset + spaceSize / 2;

                if (order > 0)
                    return position + (order * spaceSize / 3) + spaceSize / 4;

                return position;
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the value of the <see cref="Order"/> property.
        /// </summary>
        private int order;

        #endregion
    }
}
